#include <omp.h>
#include <wx/event.h>

#include "cpdfreader.h"
#include "cpdfcanvas.h"
#include "cpdfpanel.hpp"

BEGIN_EVENT_TABLE( CPdfReader , wxScrolledWindow )
    EVT_SCROLLWIN_BOTTOM( CPdfReader::OnScrollBottom )
    EVT_SCROLLWIN_TOP( CPdfReader::OnScrollTop )
    EVT_SCROLLWIN_LINEDOWN( CPdfReader::OnScrollLineDown )
    EVT_SCROLLWIN_LINEUP( CPdfReader::OnScrollLineUp )
    EVT_SCROLLWIN_THUMBTRACK( CPdfReader::OnScrollThumb )
END_EVENT_TABLE()

void CPdfReader :: OnScrollThumb( wxScrollWinEvent& evt )
{
// TODO (Administrator#6#): 添加拖动滚动杠的代码

}

void CPdfReader::OnScrollLineUp( wxScrollWinEvent& evt )
{
    if( p_doc == NULL ) return;
    if( evt.GetOrientation() ==wxVERTICAL ){
        int pos_y , pos_x;
        GetViewStart( &pos_x , &pos_y );
        pos_y *= 10;
        //计算当前页面编号
        m_current_page = pos_y / ( m_page_h + m_v_gap );
        m_current_pos = ( pos_y % ( m_page_h + m_v_gap ) ) - m_v_gap;
        ((CPdfPanel*)GetParent())->SetPages( m_current_page , p_doc->pages());

        if( m_current_page < m_page_rendered_low + 2 ){//对页面进行预先绘制
            if( m_page_rendered_low > 0 ){

                m_page_rendered_up --;
                m_page_rendered_low --;

                poppler::page *p_page = p_doc->create_page( m_page_rendered_low );
                CPdfCanvas *canvas = new CPdfCanvas( this ,  p_page );
                canvas->Render( p_page );

                delete m_pages.at( m_page_rendered_low );
                m_pages[ m_page_rendered_low ] = canvas;

                draw_page( m_page_rendered_low );
            }
        }
    }
    evt.Skip();
}

void CPdfReader::OnScrollLineDown( wxScrollWinEvent& evt )
{
    //计算当前页面和当前页面的位置
    if( p_doc == NULL ) return;
    if( evt.GetOrientation() ==wxVERTICAL ){
        int pos_y , pos_x;
        GetViewStart( &pos_x , &pos_y );
        //计算当前页面编号
        pos_y *= 10;
        m_current_page = pos_y / ( m_page_h + m_v_gap );
        m_current_pos = ( pos_y % ( m_page_h + m_v_gap ) ) - m_v_gap;
        ((CPdfPanel*)GetParent())->SetPages( m_current_page , p_doc->pages());

        if( m_current_page > m_page_rendered_up - 2 ){//对页面进行预先绘制
            if( m_page_rendered_up < p_doc->pages() - 1 ){
                m_page_rendered_up ++;
                m_page_rendered_low ++;
                poppler::page *p_page = p_doc->create_page( m_page_rendered_up );
                CPdfCanvas *canvas = new CPdfCanvas( this ,  p_page );
                canvas->Render( p_page );
                if( m_pages.size() <= m_page_rendered_up )
                    m_pages.push_back(  canvas );
                else{
                    delete (m_pages.at( m_page_rendered_up ));
                    m_pages[ m_page_rendered_up ] = canvas;
                }
                draw_page( m_page_rendered_up );
            }
        }
    }

    evt.Skip();
}

void CPdfReader::OnScrollTop( wxScrollWinEvent& evt )
{
    evt.Skip();
}

void CPdfReader::OnScrollBottom( wxScrollWinEvent& evt )
{
    evt.Skip();
}

CPdfReader :: CPdfReader() : wxScrolledWindow()
{
    m_pages.erase( m_pages.begin() , m_pages.end() );       //阅读器的页面
    m_h_gap = 5;                                             //页面的水平间隙
    m_v_gap = 5;                                             //页面的垂直间隙
    m_col_count = 1;                                         //列数量
    m_bk_color = wxColour( 128,128,128 );                    //窗口的背景色
    m_current_page = -1;                                     //当前页面
    m_page_rendered_up = -1;
    m_page_rendered_low = -1;
    //m_is_need_render = false;

    p_doc = NULL;                                            //PDF文件
}

void CPdfReader :: OnMouseRightUp( wxMouseEvent& evt )
{
    evt.Skip();
}

CPdfReader :: CPdfReader( wxWindow* parent ,
               wxWindowID id ,
               const wxPoint& pos ,
               const wxSize& size ,
               long style ,
               const wxString& name ):wxScrolledWindow( parent , id , pos , size , style , name )
{

    m_pages.erase( m_pages.begin() , m_pages.end() );       //阅读器的页面

    SetVirtualSize( GetClientSize() );
    SetScrollRate( 10, 10 );

    m_h_gap = 5;       //页面的水平间隙
    m_v_gap = 5;       //页面的垂直间隙
    m_col_count = 1;   //列数量
    m_bk_color = wxColour( 128,128,128 );    //窗口的背景色
    SetBackgroundColour( m_bk_color );

    m_current_page = -1; //当前页面
    m_page_rendered_up = -1;
//    m_is_need_render = false;

    p_doc = NULL;        //PDF文件
}

CPdfReader :: ~CPdfReader()
{
    Pages::iterator it;
    for( it = m_pages.begin(); it < m_pages.end(); it ++ ){
        if( (*it) != NULL ){
            delete (*it);
        }
    }

}

bool CPdfReader :: Create(wxWindow* parent ,
               wxWindowID id ,
               const wxPoint& pos ,
               const wxSize& size ,
               long style ,
               const wxString& name )
{
    bool ret = false;
    ret = wxScrolledWindow::Create( parent , id , pos , size , style , name );

    m_pages.erase( m_pages.begin() , m_pages.end() );       //阅读器的页面
    m_h_gap = 5;                                            //页面的水平间隙
    m_v_gap = 5;                                            //页面的垂直间隙
    m_col_count = 1;                                        //列数量
    m_bk_color = wxColour( 128,128,128 );                   //窗口的背景色
    SetBackgroundColour( m_bk_color );
    m_current_page = -1;                                    //当前页面
    m_page_rendered_up = -1;
//    m_is_need_render = false;

    p_doc = NULL;                                           //PDF文件

    return ret;
}

int CPdfReader :: Open( const std::string& file , double scale )
{
    int ret = 0;
    if( file.empty() ) return ERR_NO_FILE_NAME;
    if( p_doc != NULL ) delete p_doc;

    p_doc = poppler::document::load_from_file( file );
    if( p_doc != NULL ){
        //抽取文档信息
        int count = p_doc->pages();         //文档页面数量
        //载入页面，采用openMP的方式循环载入页面
        //#pragma omp parallel for
        for( int i = 0; i < count; i ++ ){
            poppler::page *p_page = p_doc->create_page( i );
            if( p_page != NULL ){
                CPdfCanvas *canvas = new CPdfCanvas( this , p_page );
                canvas->Render( p_page );
                m_pages.push_back(  canvas );

                wxImage img = canvas->GetImage();
                //显示页面
                draw_page( i );
                //调整滚动条的范围

                //指定当前页面
                m_current_page = 0;
            }
            else{
                ret = ERR_CREATE_PAGE;
#if defined( __DEBUG__ )
                std::cerr << "FILE:" << __FILE__ <<" At( " << __LINE__ << ") Can not create pdf page in poppler " << std::endl;
#else
                std::cerr << "Can not create pdf page in poppler " << std::endl;
#endif // defined
                i = count;
            }
        }
        ret = 0;
    }
    else{
        ret = ERR_OPEN_PDF_FILE;
#if defined( __DEBUG__ )
                std::cerr << "FILE:" << __FILE__ <<" At( " << __LINE__ << ") Can not open pdf file in poppler " << std::endl;
                std::cerr << "The PDF file name is: " << file << std::endl;
#else
                std::cerr << "Can not pdf file in poppler " << std::endl;
#endif // defined
    }
    return ret;
}

int CPdfReader :: Open( const wxString& file , double scale  )
{
    int ret = 0;
    if( file.IsEmpty() ) return ERR_NO_FILE_NAME;
    if( p_doc != NULL ) delete p_doc;

    std::string str = std::string( file.mb_str());

    p_doc = poppler::document::load_from_file( str );
    if( p_doc != NULL ){
        //抽取文档信息
        int count = p_doc->pages();         //文档页面数量

        for( int i = 0; i < count && i < 3; i ++ ){
            poppler::page *p_page = p_doc->create_page( i );
            if( p_page != NULL ){
                CPdfCanvas *canvas = new CPdfCanvas( this ,  p_page );

                canvas->Render( p_page );
                m_pages.push_back(  canvas );

                //显示页面
                draw_page( i );
                //调整滚动条范围
                if( i == 0 ){
                    int v_x , v_y;
                    v_x = ( canvas->GetW() + m_h_gap ) * m_col_count;
                    v_y = (canvas->GetH() + m_v_gap ) * ( count / m_col_count );
                    SetVirtualSize( wxSize( v_x , v_y ));
                    m_page_h = canvas->GetH();
                    m_page_w = canvas->GetW();
                }

                m_current_page = 0;
                m_page_rendered_low = 0;
                m_page_rendered_up = 2;
            }
            else{
                ret = ERR_CREATE_PAGE;
#if defined( __DEBUG__ )
                std::cerr << "FILE:" << __FILE__ <<" At( " << __LINE__ << ") Can not create pdf page in poppler " << std::endl;
#else
                std::cerr << "Can not create pdf page in poppler " << std::endl;
#endif // defined
                return ret;
            }
        }
        //指定页码1为当前页码
        Refresh();
        ret = 0;
    }
    else{
        ret = ERR_OPEN_PDF_FILE;
#if defined( __DEBUG__ )
        std::cerr << "FILE:" << __FILE__ <<" At( " << __LINE__ << ") Can not open pdf file in poppler " << std::endl;
        std::cerr << "The PDF file name is: " << file << std::endl;
#else
        std::cerr << "Can not pdf file in poppler " << std::endl;
#endif // defined
    }
    return ret;
}

int CPdfReader :: Scale( double scale )
{
    int ret = 0,count;
    count = p_doc->pages();
    for( int i = m_current_page - 2 ; i < m_current_page + 2 && i < p_doc->pages(); i ++ ){
        if( i < 0 ) continue;
        m_pages.at( i )->Scale( scale );

        if( i == 0 ){
            int v_x , v_y;
            v_x = ( m_pages.at( 0 )->GetW() + m_h_gap ) * m_col_count;
            v_y = (m_pages.at( 0 )->GetH() + m_v_gap ) * ( count / m_col_count );
            m_page_h = m_pages.at( 0 )->GetH();
            m_page_w = m_pages.at( 0 )->GetW();
            wxPoint p = GetPosition();
            p.y = ( m_current_page * ( m_page_h + m_v_gap ) + m_v_gap )/10;
            SetPosition( p );
            SetVirtualSize( wxSize( v_x , v_y ));
        }
        draw_page( i );
    }

    Refresh();
    return ret;
}

int CPdfReader :: Scale( int p_i , double scale )
{
    int ret = 0;

    return ret;
}

int CPdfReader :: Rotate( poppler::rotation_enum  angle )
{
    int ret = 0,count;

    count = p_doc->pages();
    wxImage img;
    for( int i = 0; i < count; i ++ ){
        m_pages.at( i )->SetOrient( angle );
        img = m_pages.at( i )->GetImage();
        draw_page( i );
    }

    return ret;
}

int CPdfReader :: Rotate( int p_i , poppler::rotation_enum  angle )
{
    int ret = 0;
     wxImage img;
    if( p_i >= 0 && p_i < m_pages.size() ){
        m_pages.at( p_i )->SetOrient( angle );
        img = m_pages.at( p_i )->GetImage();
        draw_page( p_i );
    }
    //#pragma omp parallel for
    for( int i = p_i + 1 ; i < m_pages.size(); i ++ ){
        img = m_pages.at( i )->GetImage();
        ret = draw_page( i );
    }
    return ret;
}

void CPdfReader :: SetPageGap( int h_gap , int v_gap )
{
    m_h_gap = h_gap;
    m_v_gap = v_gap;
}

int CPdfReader :: GetCount()
{
    return p_doc->pages();
}

int CPdfReader :: draw_page( int index )
{
    int ret = 0;
    int row = 0 , col = 0;
    //计算图片要显示的行列位置
    row = index / m_col_count;
    col = index % m_col_count;
    //如果图片的尺寸小于窗口，则将图片显示在窗口中间
    int x , y , c_x , c_y;
    if( index > m_pages.size()) return -1;

    if( col != 0 )
        x = m_pages.at(index  )->GetW() + m_h_gap * col;
    else
        x = m_h_gap;
    //将图片调整对中
    GetClientSize(&c_x , &c_y );
    if( m_pages.at(index  )->GetW() + m_h_gap * col < c_x ){
        x = ( c_x - m_pages.at(index )->GetW() ) / 2;
    }

    if( row != 0 ){
        y =  (m_pages[index]->GetH() + m_v_gap ) * row + m_v_gap;
    }
    else{
        y = m_v_gap;
    }

    //调整图片位置
    m_pages.at(index )->SetPos( x , y );

    return ret;
}

int CPdfReader :: get_page_pos( wxPoint& pos , poppler::page *page )
{
    int ret = 0;

    return ret;
}

int CPdfReader :: get_page_rect( wxRect& rect , poppler::page *page )
{
    int ret = 0;

    return ret;
}

int CPdfReader :: get_page_size( wxPoint& size , poppler::page *page )
{
    int ret = 0;

    return ret;
}

void CPdfReader :: OnDraw( wxDC& dc )
{
    for( int i = 0; i < m_pages.size(); i ++ ){
        if( i < m_current_page - 2 || i > m_current_page + 2 )
            m_pages[ i ]->ClearImage();
    }
    for( int i = m_current_page - 2 ; p_doc != NULL && i < m_current_page + 2 && i < p_doc->pages(); i ++){
        //(*it)->Render();
        if( i < 0 )continue;
        if( i > m_pages.size() - 1 ) return;
        if( m_pages[ i ]->IsPageOK() ){
            draw_page( i );
            wxBitmap bmp(m_pages[i]->GetImage());
            //(*it)->ClearImage();
            dc.DrawBitmap(bmp , m_pages[i]->GetX() , m_pages[i]->GetY() );
        }
    }
}


void CPdfReader :: NextPage()
{
    m_current_page ++;
    if( m_current_page >= p_doc->pages() ) m_current_page = p_doc->pages() - 1;

    ((CPdfPanel*)GetParent())->SetPages( m_current_page , p_doc->pages());

    if( m_current_page > m_page_rendered_up - 2 ){//对页面进行预先绘制
        if( m_page_rendered_up < p_doc->pages() - 1 ){
            m_page_rendered_up ++;
            m_page_rendered_low ++;
            poppler::page *p_page = p_doc->create_page( m_page_rendered_up );
            CPdfCanvas *canvas = new CPdfCanvas( this ,  p_page );
            canvas->Render( p_page );
            if( m_pages.size() <= m_page_rendered_up )
                m_pages.push_back(  canvas );
            else{
                delete (m_pages.at( m_page_rendered_up ));
                m_pages[ m_page_rendered_up ] = canvas;
            }
            draw_page( m_page_rendered_up );
        }
    }
}

void CPdfReader :: PrePage()
{
    m_current_page --;
    if( m_current_page <= 0 ) m_current_page = 0;

    if( m_current_page < m_page_rendered_low + 2 ){//对页面进行预先绘制
        if( m_page_rendered_low > 0 ){

            m_page_rendered_up --;
            m_page_rendered_low --;

            poppler::page *p_page = p_doc->create_page( m_page_rendered_low );
            CPdfCanvas *canvas = new CPdfCanvas( this ,  p_page );
            canvas->Render( p_page );

            delete m_pages.at( m_page_rendered_low );
            m_pages[ m_page_rendered_low ] = canvas;

            draw_page( m_page_rendered_low );
        }
    }
}

void CPdfReader :: GotoPage( int index )
{/*
    int old_page = m_current_page;
    m_current_page = index;
    for( int i = m_current_page - 2 ; i < m_current_page + 2 && i < p_doc->pages(); i ++ ){
        if( i < 0 ) continue;
        poppler::page *p_page = p_doc->create_page( i );
        CPdfCanvas *p_canvs = new CPdfCanvas( this , p_page ,  m_orient , m_pages[ old_page ]->GetScale() ,m_x_res , m_y_res );
        p_canvs->Render( p_page );
        if( i >= m_pages.size() ){
            m_pages.resize( m_current_page + 2 );
        }
        if( m_pages[ i ] != NULL ) delete (m_pages[ i ]);
        m_pages[ i ] = p_canvs;
        draw_page( i );
    }
    Refresh();
    */
}

void CPdfReader :: CloseFile()
{
    if( p_doc != NULL )
        delete p_doc;
    p_doc = NULL;
    Pages::iterator it;
    for( it = m_pages.begin(); it < m_pages.end(); it ++ ){
        if( (*it) != NULL ){
            delete (*it);
        }
    }
    m_pages.erase( m_pages.begin() , m_pages.end());
}
